/**
 * 性能优化工具函数
 * 包含防抖、节流、数据采样等工具
 */

/**
 * 防抖函数 - 延迟执行，多次触发只执行最后一次
 * @param {Function} func - 要执行的函数
 * @param {number} wait - 等待时间(毫秒)
 * @param {boolean} immediate - 是否立即执行
 * @returns {Function} 防抖后的函数
 */
export function debounce(func, wait = 300, immediate = false) {
  let timeout

  return function executedFunction(...args) {
    const context = this

    const later = () => {
      timeout = null
      if (!immediate) func.apply(context, args)
    }

    const callNow = immediate && !timeout

    clearTimeout(timeout)
    timeout = setTimeout(later, wait)

    if (callNow) func.apply(context, args)
  }
}

/**
 * 节流函数 - 限制执行频率
 * @param {Function} func - 要执行的函数
 * @param {number} limit - 时间限制(毫秒)
 * @returns {Function} 节流后的函数
 */
export function throttle(func, limit = 300) {
  let inThrottle

  return function executedFunction(...args) {
    const context = this

    if (!inThrottle) {
      func.apply(context, args)
      inThrottle = true
      setTimeout(() => {
        inThrottle = false
      }, limit)
    }
  }
}

/**
 * 数据采样 - 减少大数据集的数据点
 * @param {Array} data - 原始数据数组
 * @param {number} maxPoints - 最大数据点数
 * @param {string} strategy - 采样策略 ('uniform', 'lttb', 'downsample')
 * @returns {Array} 采样后的数据
 */
export function sampleData(data, maxPoints = 1000, strategy = 'uniform') {
  if (!data || data.length <= maxPoints) {
    return data
  }

  switch (strategy) {
    case 'lttb':
      // Largest Triangle Three Buckets 算法
      return lttbSample(data, maxPoints)
    case 'downsample':
      // 下采样 - 取平均值
      return downsample(data, maxPoints)
    case 'uniform':
    default:
      // 均匀采样
      return uniformSample(data, maxPoints)
  }
}

/**
 * 均匀采样
 * @private
 */
function uniformSample(data, maxPoints) {
  const step = Math.ceil(data.length / maxPoints)
  const sampled = []

  for (let i = 0; i < data.length; i += step) {
    sampled.push(data[i])
  }

  // 确保包含最后一个数据点
  if (sampled[sampled.length - 1] !== data[data.length - 1]) {
    sampled.push(data[data.length - 1])
  }

  return sampled
}

/**
 * 下采样 - 分组取平均
 * @private
 */
function downsample(data, maxPoints) {
  const bucketSize = Math.ceil(data.length / maxPoints)
  const sampled = []

  for (let i = 0; i < data.length; i += bucketSize) {
    const bucket = data.slice(i, i + bucketSize)

    // 对数值字段取平均值
    const averaged = {}
    const firstItem = bucket[0]

    Object.keys(firstItem).forEach(key => {
      if (typeof firstItem[key] === 'number') {
        averaged[key] = bucket.reduce((sum, item) => sum + (item[key] || 0), 0) / bucket.length
      } else {
        averaged[key] = firstItem[key] // 非数值字段取第一个值
      }
    })

    sampled.push(averaged)
  }

  return sampled
}

/**
 * LTTB (Largest Triangle Three Buckets) 采样算法
 * 保留数据的视觉特征
 * @private
 */
function lttbSample(data, maxPoints) {
  if (data.length <= maxPoints) {
    return data
  }

  const sampled = []
  const bucketSize = (data.length - 2) / (maxPoints - 2)

  // 总是包含第一个点
  sampled.push(data[0])

  let a = 0 // 上一个选中的点

  for (let i = 0; i < maxPoints - 2; i++) {
    // 计算当前桶的平均点
    const avgRangeStart = Math.floor((i + 1) * bucketSize) + 1
    const avgRangeEnd = Math.floor((i + 2) * bucketSize) + 1
    const avgRangeLength = avgRangeEnd - avgRangeStart

    let avgX = 0
    let avgY = 0

    for (let j = avgRangeStart; j < avgRangeEnd && j < data.length; j++) {
      avgX += j
      // 假设第一个数值字段是 Y 值
      const yValue = Object.values(data[j]).find(v => typeof v === 'number') || 0
      avgY += yValue
    }
    avgX /= avgRangeLength
    avgY /= avgRangeLength

    // 在当前桶中找到形成最大三角形的点
    const rangeStart = Math.floor(i * bucketSize) + 1
    const rangeEnd = Math.floor((i + 1) * bucketSize) + 1

    let maxArea = -1
    let maxAreaPoint = rangeStart

    const pointA = data[a]
    const aX = a
    const aY = Object.values(pointA).find(v => typeof v === 'number') || 0

    for (let j = rangeStart; j < rangeEnd && j < data.length; j++) {
      const pointB = data[j]
      const bY = Object.values(pointB).find(v => typeof v === 'number') || 0

      // 计算三角形面积
      const area = Math.abs(
        (aX - avgX) * (bY - aY) - (aX - j) * (avgY - aY)
      ) * 0.5

      if (area > maxArea) {
        maxArea = area
        maxAreaPoint = j
      }
    }

    sampled.push(data[maxAreaPoint])
    a = maxAreaPoint
  }

  // 总是包含最后一个点
  sampled.push(data[data.length - 1])

  return sampled
}

/**
 * 批量处理 - 将大数组分批处理，避免阻塞主线程
 * @param {Array} items - 要处理的项目数组
 * @param {Function} processFn - 处理函数
 * @param {number} batchSize - 批次大小
 * @returns {Promise} 处理完成的 Promise
 */
export async function batchProcess(items, processFn, batchSize = 100) {
  const results = []

  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize)
    const batchResults = await Promise.all(batch.map(processFn))
    results.push(...batchResults)

    // 允许浏览器渲染
    await new Promise(resolve => setTimeout(resolve, 0))
  }

  return results
}

/**
 * 内存优化的大数据分页
 * @param {Array} data - 完整数据
 * @param {number} page - 页码(从1开始)
 * @param {number} pageSize - 每页大小
 * @returns {Object} 分页结果
 */
export function paginate(data, page = 1, pageSize = 100) {
  const totalPages = Math.ceil(data.length / pageSize)
  const start = (page - 1) * pageSize
  const end = start + pageSize

  return {
    data: data.slice(start, end),
    page,
    pageSize,
    total: data.length,
    totalPages,
    hasNext: page < totalPages,
    hasPrev: page > 1
  }
}

/**
 * 深度克隆对象（性能优化版）
 * @param {*} obj - 要克隆的对象
 * @returns {*} 克隆后的对象
 */
export function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj
  }

  // 使用结构化克隆（如果可用，性能更好）
  if (typeof structuredClone === 'function') {
    try {
      return structuredClone(obj)
    } catch (e) {
      // 降级到手动克隆
    }
  }

  // 数组
  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item))
  }

  // 对象
  const cloned = {}
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key])
    }
  }

  return cloned
}

/**
 * LRU (Least Recently Used) 缓存实现
 */
export class LRUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize
    this.cache = new Map()
  }

  get(key) {
    if (!this.cache.has(key)) {
      return null
    }

    // 移到末尾（最近使用）
    const value = this.cache.get(key)
    this.cache.delete(key)
    this.cache.set(key, value)

    return value
  }

  set(key, value) {
    // 如果已存在，先删除
    if (this.cache.has(key)) {
      this.cache.delete(key)
    }

    // 添加到末尾
    this.cache.set(key, value)

    // 如果超过容量，删除最旧的（第一个）
    if (this.cache.size > this.maxSize) {
      const firstKey = this.cache.keys().next().value
      this.cache.delete(firstKey)
    }
  }

  has(key) {
    return this.cache.has(key)
  }

  delete(key) {
    return this.cache.delete(key)
  }

  clear() {
    this.cache.clear()
  }

  get size() {
    return this.cache.size
  }
}

/**
 * 简单的性能监控装饰器
 * @param {string} operationName - 操作名称
 * @returns {Function} 装饰器函数
 */
export function measurePerformance(operationName) {
  return function (target, propertyKey, descriptor) {
    const originalMethod = descriptor.value

    descriptor.value = async function (...args) {
      const startTime = performance.now()
      const startMemory = performance.memory ? performance.memory.usedJSHeapSize : null

      try {
        const result = await originalMethod.apply(this, args)
        const duration = performance.now() - startTime

        console.log(`[PERF] ${operationName || propertyKey}: ${duration.toFixed(2)}ms`)

        return result
      } catch (error) {
        const duration = performance.now() - startTime
        console.error(`[PERF] ${operationName || propertyKey} failed after ${duration.toFixed(2)}ms`, error)
        throw error
      }
    }

    return descriptor
  }
}

export default {
  debounce,
  throttle,
  sampleData,
  batchProcess,
  paginate,
  deepClone,
  LRUCache,
  measurePerformance
}
